package com.imooc.controller;

import com.imooc.pojo.Users;
import com.imooc.pojo.bo.ShopcartBO;
import com.imooc.pojo.bo.UserBo;
import com.imooc.pojo.vo.UsersVO;
import com.imooc.service.UserService;
import com.imooc.utils.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;

@Api(value = "注册登录", tags = {"用于注册登录的相关接口"})
@RestController
@RequestMapping("passport")
public class PassportController extends BaseController {

    @Autowired
    private UserService userService;

    @Autowired
    private RedisOperator redisOperator;

    @ApiOperation(value = "用户名是否存在", notes = "用户名是否存在", httpMethod = "GET") //用于阐述当前方法的含义
    @GetMapping("/usernameIsExist")
    public IMOOCJSONResult usernameIsExist(@RequestParam String username) {
        //这里用的是apache的lang3包的StringUtil工具类,blank对比empty多一个空字符串的判定,首先要判空
        //1.判空
        if (StringUtils.isBlank(username)) {
            //500
            return IMOOCJSONResult.errorMsg("用户名不能为空");
        }
        //2.查找注册用户名是否存在
        boolean isExist = userService.queryUsernameIsExist(username);
        if (isExist) {
            //500
            return IMOOCJSONResult.errorMsg("用户名已经存在");
        }
        //3.请求成功,用户名没有重复 状态码200
        return IMOOCJSONResult.ok();
    }

    @ApiOperation(value = "用户注册", notes = "用户注册", httpMethod = "POST") //用于阐述当前方法的含义
    @PostMapping("/regist")
    public IMOOCJSONResult regist(@RequestBody UserBo userBo, HttpServletRequest request,
                                  HttpServletResponse response) {
        String username = userBo.getUsername();
        String password = userBo.getPassword();
        String confirmPwd = userBo.getConfirmPassword();

        //0.判断用户名和密码不为空
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password) || StringUtils.isBlank(confirmPwd)) {
            return IMOOCJSONResult.errorMsg("用户名或密码不能为空");
        }

        //1.查询用户名是否存在
        boolean isExist = userService.queryUsernameIsExist(username);
        if (isExist) {
            return IMOOCJSONResult.errorMsg("用户名已经存在");
        }
        //2.密码长度不能少于6位校验
        if (password.length() < 6) {
            return IMOOCJSONResult.errorMsg("密码长度不能少于6位");
        }
        //3.判断两次密码是否一致
        if (!password.equals(confirmPwd)) {
            return IMOOCJSONResult.errorMsg("两次密码输入不一致");
        }
        //4.实现注册
        Users userResult = userService.createUser(userBo);

        //实现用户的redis会话
        UsersVO usersVO = convertUsersVO(userResult);

        //这里我是从登录搬过来的,因为注册后可以有一个默认登录的设置,所以进行一个cookie保存操作
        //这里我们要把用户敏感数据不返回,置为空就可以了
        // userResult = setNullProperty(userResult); 我们使用UsersVO就可以删除

        //要使用cookie,键为user,值为String类型并且加密
        CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true);
        synchShopcartData(userResult.getId(), request, response);
        return IMOOCJSONResult.ok();
    }

    @ApiOperation(value = "用户登录", notes = "用户登录", httpMethod = "POST") //用于阐述当前方法的含义
    @PostMapping("/login")
    public IMOOCJSONResult login(@RequestBody UserBo userBo, HttpServletRequest request,
                                 HttpServletResponse response) throws Exception {
        String username = userBo.getUsername();
        String password = userBo.getPassword();

        //0.判断用户名和密码不为空
        if (StringUtils.isBlank(username) || StringUtils.isBlank(password)) {
            return IMOOCJSONResult.errorMsg("用户名或密码不能为空");
        }

        //1.实现登录
        Users userResult = userService.queryUserForLogin(username, MD5Utils.getMD5Str(password));

        if (userResult == null) {
            return IMOOCJSONResult.errorMsg("用户名或者密码不正确");
        }
        //这里我们要把用户敏感数据不返回,置为空就可以了
        // userResult = setNullProperty(userResult);
        //要使用cookie,键为user,值为String类型并且加密

        //HAVETODO 生成用户token,存入redis会话
        UsersVO usersVO = convertUsersVO(userResult);
        CookieUtils.setCookie(request, response, "user", JsonUtils.objectToJson(usersVO), true);

        //HAVETODO 同步购物车数据(场景:如果用户登陆过并设置了购物车,换台电脑也要同步购物车)
        synchShopcartData(userResult.getId(), request, response);
        return IMOOCJSONResult.ok(userResult);
    }

    /**
     * 注册登录成功后,同步cookie和redis中的购物车数据
     */
    public void synchShopcartData(String userId, HttpServletRequest request,
                                  HttpServletResponse response) {
        /**
         * redis中无数据,如果cookie中的购物车为空,那么这个时候不做任何的处理
         *              如果cookie中的购物车不为空,则将cookie购物车同步到redis
         * redis有数据,cookie为空,则将redis覆盖cookie
         *              如果cookie不为空,则以cookie为准(参考京东的做法)覆盖redis,也可以使用淘宝的做法,只有登录后才能在购物车中添加数据
         *
         * 同步到redis中去后,覆盖本地cookie中的数据,保证本地购物车数据同步
         */
        //1.从redis中获取购物车
        String shopcartJsonRedis = redisOperator.get(FOODIE_SHOPCART + ":" + userId);

        //2.从cookie获取购物车
        String shopcartCookie = CookieUtils.getCookieValue(request, FOODIE_SHOPCART, true);

        if (StringUtils.isBlank(shopcartJsonRedis)) {
            if (StringUtils.isNotBlank(shopcartCookie)) {
                redisOperator.set(FOODIE_SHOPCART + ":" + userId, shopcartCookie);
            }
        } else {
            //我们这里合并cookie和redis缓存
            if (StringUtils.isNotBlank(shopcartCookie)) {

                //1.如果购物车已经存在的商品,根据cookie对应的商品数量覆盖redis(参考京东)或者累加,这个无所谓
                //2.该项商品要标记为待删除,统一放入一个待删除的list
                //3.从cookie中清理所有的待删除list
                //4.合并redis和cookie的数据
                //5.将合并最新的数据更新到redis和cookie

                List<ShopcartBO> shopcartListRedis = JsonUtils.jsonToList(shopcartJsonRedis, ShopcartBO.class);

                List<ShopcartBO> shopcartListCookie = JsonUtils.jsonToList(shopcartCookie, ShopcartBO.class);

                //等待删除处理的list
                List<ShopcartBO> pendingDeleteList = new ArrayList<>();

                for (ShopcartBO redisShopcartBO : shopcartListRedis) {
                    String redisSpecId = redisShopcartBO.getSpecId();
                    for (ShopcartBO cookieShopcart : shopcartListRedis) {
                        String cookieSpecId = cookieShopcart.getSpecId();
                        //如果cookie和redisSpecId相同,以cookie为准覆盖redis的数量
                        if (cookieSpecId == redisSpecId) {
                            redisShopcartBO.setBuyCounts(cookieShopcart.getBuyCounts());
                            pendingDeleteList.add(cookieShopcart);
                        }
                    }
                }
                shopcartListCookie.removeAll(pendingDeleteList);

                //合并两个list,shopcartListCookie已经被移除了所有重复数据,以redis为准,只有buycounts以cookie为准
                shopcartListRedis.addAll(shopcartListCookie);

                //更新到cookie
                CookieUtils.setCookie(request, response,
                        FOODIE_SHOPCART, JsonUtils.objectToJson(shopcartListRedis), true);

                //更新redis
                redisOperator.set(FOODIE_SHOPCART + ":" + userId, JsonUtils.objectToJson(shopcartListRedis));

            } else {
                CookieUtils.setCookie(request, response,
                        FOODIE_SHOPCART, shopcartJsonRedis, true);
            }
        }

    }

    private Users setNullProperty(Users userResult) {
        userResult.setPassword(null);
        userResult.setMobile(null);
        userResult.setEmail(null);
        userResult.setUpdatedTime(null);
        userResult.setCreatedTime(null);
        userResult.setBirthday(null);
        return userResult;
    }

    @ApiOperation(value = "用户退出登录", notes = "用户退出登录", httpMethod = "POST") //用于阐述当前方法的含义
    @PostMapping("/logout")
    public IMOOCJSONResult logout(@RequestParam String userId, HttpServletRequest request,
                                  HttpServletResponse response) {
        //清除用户相关信息的cookie,场景:比如我在网吧,登出后还是存在cookie,虽然我们加密过,但是还是有安全隐患
        CookieUtils.deleteCookie(request, response, "user");

        //HAVETODO 用户退出登录需要清空购物车
        CookieUtils.deleteCookie(request, response, FOODIE_SHOPCART);
        //DONETODO 分布式会话也要清除用户数据
        /**
         * 用户退出登录清除购物车
         */
        //清除redis的用户登录信息缓存
        redisOperator.del(REDIS_USER_TOKEN + ":" + userId);

        return IMOOCJSONResult.ok();
    }

}